#include "io_config.h"
#if API_ENABLE_FILE_MANAGER
#include "http_server.h"
#include "api_map.h"
#include "file_tool.h"

static void get_file(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    if (cJSON_HasObjectItem(data, "path"))
    {
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        if (file_exist(path)) /* 获取文件 */
        {
            FILE *fd = fopen(path, "r");
            if (fd)
            {
                fseek(fd, 0, SEEK_END);
                uint32_t file_size = ftell(fd);
                char buffer[128] = {0};
                snprintf(buffer, sizeof(buffer), "{\"size\":%ld}", file_size);
                ws_reply_data(server, frame, "get_file", buffer);
                httpd_ws_send_frame(server->cur_req, frame);
                frame->len = 0;
                fseek(fd, 0, SEEK_SET);
                uint16_t size = sizeof(server->data) > 4096 ? 4096 : sizeof(server->data);
                uint32_t read_size;
                uint32_t read_count = 0;
                do
                {
                    read_size = fread(server->data, 1, size, fd);
                    if (read_size)
                    {
                        frame->len = read_size;
                        httpd_ws_send_frame(server->cur_req, frame);
                        read_count += read_size;
                        if (read_size != size)
                            break;
                    }
                } while (read_size);
                frame->len = 0;
                if (read_count != file_size)
                    ws_reply_status(server, frame, "get_file", -2); /* 读取途中失败 */
                fclose(fd);
                return;
            }
        }
    }
    ws_reply_status(server, frame, "get_file", -1);
}

static void get_files(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    uint16_t len = 0;
    char *str = (char *)server->data;
    len += sprintf(&str[len], "{");
    len += sprintf(&str[len], "\"api\":\"get_files\",");
    len += sprintf(&str[len], "\"data\":");
    if (cJSON_HasObjectItem(data, "path"))
    {
        char path_buff[256];
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        strcpy(path_buff, path);
        if (!strcmp(path, "/")) /* 遍历根目录 */
            len += list_files_to(path_buff, &str[len], sizeof(server->data) - len - 1);
        else if (dir_exist(path))
            len += list_files_to(path_buff, &str[len], sizeof(server->data) - len - 1);
        else
            len += sprintf(&str[len], "-1");
    }
    else
        len += sprintf(&str[len], "-1");
    len += sprintf(&str[len], "}");
    frame->payload = server->data;
    frame->len = len;
}

static void get_files_search(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    uint16_t len = 0;
    char *str = (char *)server->data;
    len += sprintf(&str[len], "{");
    len += sprintf(&str[len], "\"api\":\"get_files_search\",");
    len += sprintf(&str[len], "\"data\":");
    if (cJSON_HasObjectItem(data, "path"))
    {
        char path_buff[256];
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        strcpy(path_buff, path);
        if (cJSON_HasObjectItem(data, "name")) /* 查找文件 */
        {
            char *name = cJSON_GetObjectItem(data, "name")->valuestring;
            const char *names[] = {name, 0};
            printf("[web.file.get] find %s form %s\n", name, path_buff);
            char *list = &str[len];
            len += sprintf(&str[len], "[");
            uint32_t size = find_files_to(path_buff, names, &str[len], sizeof(server->data) - len - 1);
            if (size)
            {
                len += size;
                len -= 1;
                printf("[web.file.search] List:  %s\n", list);
            }
            len += sprintf(&str[len], "]");
        }
    }
    else
        len += sprintf(&str[len], "-1");
    len += sprintf(&str[len], "}");
    frame->payload = server->data;
    frame->len = len;
}

static void create_file(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    int8_t ret = -1;
    if (cJSON_HasObjectItem(data, "path"))
    {
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        char *p = strrchr(path, '/');
        if (p && p != path)
        {
            p[0] = '\0';
            mkdirs(path);
            p[0] = '/';
        }
        FILE *fd = fopen(path, "w");
        if (fd)
        {
            if (cJSON_HasObjectItem(data, "content"))
            {
                char *content = cJSON_GetObjectItem(data, "content")->valuestring;
                if (cJSON_HasObjectItem(data, "offset"))
                    fseek(fd, cJSON_GetInt(data, "offset"), SEEK_CUR);
                fwrite(content, 1, strlen(content), fd);
            }
            fclose(fd);
            ret = 0; /* 创建成功 */
        }
        else
            ret = -2; /* 创建失败 */
    }
    ws_reply_status(server, frame, "create_file", ret);
}

static void create_folder(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    int8_t ret = -1;
    if (cJSON_HasObjectItem(data, "path"))
    {
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        char *p = strrchr(path, '/');
        if (p && p != path)
            printf("Create folder %s %s\n", path, mkdirs(path) ? "success" : "fail");
        if (dir_exist(path)) /* 创建文件夹 */
            ret = 0;         /* 创建成功 */
        else
            ret = -2; /* 创建失败 */
    }
    ws_reply_status(server, frame, "create_folder", ret);
}

static void delete_file(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    int8_t ret = -1;
    if (cJSON_HasObjectItem(data, "path"))
    {
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        if (file_exist(path)) /* 查找文件 */
        {
            if (remove(path))
                ret = 0; /* 删除成功 */
            else
                ret = -2; /* 删除失败 */
        }
    }
    ws_reply_status(server, frame, "delete_file", ret);
}

static void delete_folder(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    int8_t ret = -1;
    if (cJSON_HasObjectItem(data, "path"))
    {
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        if (dir_exist(path)) /* 查找文件夹 */
        {
            if (rmdir(path))
                ret = 0; /* 删除成功 */
            else
                ret = -2; /* 删除失败 */
        }
    }
    ws_reply_status(server, frame, "delete_folder", ret);
}

static void file_rename(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    int8_t ret = -1;
    if (cJSON_HasObjectItem(data, "path") && cJSON_HasObjectItem(data, "name"))
    {
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        char *new_path = cJSON_GetObjectItem(data, "name")->valuestring;
        if (rename(path, new_path) == 0)
            ret = 0;
        else
            ret = -2;
    }
    ws_reply_status(server, frame, "file_rename", ret);
}

static void change_file(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    int8_t ret = -1;
    if (cJSON_HasObjectItem(data, "path") && cJSON_HasObjectItem(data, "size"))
    {
        char *path = cJSON_GetObjectItem(data, "path")->valuestring;
        if (file_exist(path)) /* 确认文件是否存在 */
        {
            if (!server->ws.file)
            {
                server->ws.file = fopen(path, "w");
                if (server->ws.file)
                {
                    server->ws.file_recv_size = 0;
                    server->ws.file_size = cJSON_GetInt(data, "size");
                    if (!server->ws.file_size)
                    {
                        fclose(server->ws.file);
                        server->ws.file = NULL;
                        ret = 1;
                    }
                    else
                        ret = 0;
                }
            }
        }
    }
    ws_reply_status(server, frame, "change_file", ret);
}

static void file_manager_init(void)
{
    ADD_API_ITEM(get_file);
    ADD_API_ITEM(get_files);
    ADD_API_ITEM(get_files_search);
    ADD_API_ITEM(create_file);
    ADD_API_ITEM(create_folder);
    ADD_API_ITEM(delete_file);
    ADD_API_ITEM(delete_folder);
    ADD_API_ITEM(file_rename);
    ADD_API_ITEM(change_file);
}
ADD_API(file_manager_init)
#endif